//
//  HHKeyboardUtil.m
//  pod
//
//  Created by lzy on 15/12/26.
//  Copyright © 2015年 lzy . All rights reserved.
//

#import "HHKeyboardUtil.h"
#import "HHKeyboardInfo.h"
#import <BCFoundation/BCFoundationUtils.h>

#define  kHHKeyboardDuration     0.4f

@interface HHKeyboardUtil()<HHKeyboardUtilProtocol>
@property (assign, nonatomic) int   appearPostIndex;
@property (strong, nonatomic) HHKeyboardInfo    *keyboardInfo;
@property (assign, nonatomic) BOOL              haveRegisterObserver;
@property (weak, nonatomic) UIView              *adaptiveView;
@property (strong, nonatomic) NSValue           *prepareRectValue;
@end


@implementation HHKeyboardUtil
//MARK: - system
- (instancetype)init {
    self = [super init];
    if (self) {
        _keyboardTopMargin = 30;
        _zhenable = YES;
        [self registerObserver];
    }
    return self;
}
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    BCLogDealloc();
}

//MARK: - setter
- (void)setPrepareRectValue:(NSValue *)prepareRectValue {
    //为nil时才设置
    if (!_prepareRectValue) {
        _prepareRectValue = prepareRectValue;
    }
}

//MARK: - private
- (void)registerObserver {
    if (YES == _haveRegisterObserver) {
        return;
    }
    self.haveRegisterObserver = YES;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
}


//MARK: - public
- (void)adaptiveViewHandleWithController:(UIViewController *)viewController adaptiveView:(UIView *)adaptiveView, ...NS_REQUIRES_NIL_TERMINATION {
    NSMutableArray *adaptiveViewList = [NSMutableArray array];
    [adaptiveViewList addObject:adaptiveView];
    
    va_list var_list;
    va_start(var_list, adaptiveView);
    UIView *view;
    while ((view = va_arg(var_list, UIView *))) {
        [adaptiveViewList addObject:view];
    }
    va_end(var_list);
    if (!viewController) {
        return;
    }
    self.adaptiveController = viewController;
    for (UIView *adaptiveViews in adaptiveViewList) {
        UIView *firstResponder = nil;
        [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];
        if (nil != firstResponder) {
            self.adaptiveView = firstResponder;
            [self fitKeyboardAutomatically:firstResponder controllerView:viewController.view keyboardRect:_keyboardInfo.frameEnd];
            break;
        }
    }
}
- (void)adaptiveViewHandleWithAdaptiveView:(UIView *)adaptiveView, ...NS_REQUIRES_NIL_TERMINATION {
    NSMutableArray *adaptiveViewList = [NSMutableArray array];
    [adaptiveViewList addObject:adaptiveView];
    va_list var_list;
    va_start(var_list, adaptiveView);
    UIView *view;
    while ((view = va_arg(var_list, UIView *))) {
        [adaptiveViewList addObject:view];
    }
    va_end(var_list);
    UIViewController *adaptiveController;
    [adaptiveView findControllerWithResultController:&adaptiveController];
    if (!adaptiveController) {
        return;
    }
    self.adaptiveController = adaptiveController;
    for (UIView *adaptiveViews in adaptiveViewList) {
        UIView *firstResponder = nil;
        [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];
        if (nil != firstResponder) {
            self.adaptiveView = firstResponder;
            [self fitKeyboardAutomatically:firstResponder controllerView:adaptiveController.view keyboardRect:_keyboardInfo.frameEnd];
            break;
        }
    }
}
- (void)adaptiveViews:(NSArray *)views {
    if (views.count<=0) {
        return;
    }
    UIView *firstView = views.firstObject;
    UIViewController *adaptiveController;
    [firstView findControllerWithResultController:&adaptiveController];
    if (!adaptiveController) {
        return;
    }
    self.adaptiveController = adaptiveController;
    for (UIView *adaptiveViews in views) {
        UIView *firstResponder = nil;
        [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];
        if (nil != firstResponder) {
            self.adaptiveView = firstResponder;
            [self fitKeyboardAutomatically:firstResponder controllerView:adaptiveController.view keyboardRect:_keyboardInfo.frameEnd];
            break;
        }
    }
}
- (void)adaptiveVC:(UIViewController *)viewController withAdaptiveViews:(NSArray *)views {
    if (views.count<=0 || !viewController) {
        return;
    }
    self.adaptiveController = viewController;
    for (UIView *adaptiveViews in views) {
        UIView *firstResponder = nil;
        [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];
        if (nil != firstResponder) {
            self.adaptiveView = firstResponder;
            [self fitKeyboardAutomatically:firstResponder controllerView:viewController.view keyboardRect:_keyboardInfo.frameEnd];
            break;
        }
    }
}
-(void)readaptiveView:(BOOL )animated {
    if (self.adaptiveViews.count <=0 || self.adaptiveController == nil) {
        return ;
    }
    @BCWeakify(self);
    void(^block)(void) = ^ {
        @BCStrongify(self);
        for (UIView *adaptiveViews in self.adaptiveViews) {
            UIView *firstResponder = nil;
            [self recursionTraverseFindFirstResponderIn:adaptiveViews responder:&firstResponder];
            if (nil != firstResponder) {
                self.adaptiveView = firstResponder;
                [self fitKeyboardAutomatically:firstResponder controllerView:self.adaptiveController.view keyboardRect:self.keyboardInfo.frameEnd];
                break;
            }
        }
    };
    if (animated) {
        [UIView animateWithDuration:kHHKeyboardDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            block();
                } completion:^(BOOL finished) {
                }];
    }
    else {
        block();
    }
}

//MARK: - 调整view

/// 在view内，找到有焦点的view
/// @param view 需要查找的view
/// @param responder 找到的焦点view
- (void)recursionTraverseFindFirstResponderIn:(UIView *)view responder:(UIView **)responder {
    if ([view isFirstResponder]) {
        *responder = view;
    } else {
        for (UIView *subView in view.subviews) {
            if ([subView isFirstResponder]) {
                *responder = subView;
                return;
            }
            [self recursionTraverseFindFirstResponderIn:subView responder:responder];
        }
    }
    return;
}
- (void)fitKeyboardAutomatically:(UIView *)adaptiveView controllerView:(UIView *)controllerView keyboardRect:(CGRect)keyboardRect {
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    CGRect convertRect = [adaptiveView.superview convertRect:adaptiveView.frame toView:window];
    if (CGRectGetMinY(keyboardRect) - _keyboardTopMargin < CGRectGetMaxY(convertRect)) {
        //记住originFrame
        self.prepareRectValue = [NSValue valueWithCGRect:controllerView.frame];
        CGFloat signedDiff = CGRectGetMinY(keyboardRect) - CGRectGetMaxY(convertRect) - _keyboardTopMargin;
        //updateOriginY
        CGFloat newOriginY = CGRectGetMinY(controllerView.frame) + signedDiff;
        controllerView.frame = CGRectMake(controllerView.frame.origin.x, newOriginY, controllerView.frame.size.width, controllerView.frame.size.height);
    }
}
- (void)autoRestoreKeyboard {
    [self textViewHandle];
    if (_prepareRectValue) {
        self.adaptiveController.view.frame = [_prepareRectValue CGRectValue];
        _prepareRectValue = nil;
    }
}
- (void)textViewHandle {
    //还原时 textView可能会出现offset错乱现象
    if ([_adaptiveView isKindOfClass:[UITextView class]]) {
        [(UITextView *)_adaptiveView setContentOffset:CGPointMake(0, 0)];
    }
}

//MARK: - 重写KeyboardInfo set方法，调用animationBlock
- (void)setKeyboardInfo:(HHKeyboardInfo *)keyboardInfo {
    //home键使应用进入后台也会有某些通知
    if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
        return;
    }
    _keyboardInfo = keyboardInfo;
    if(!keyboardInfo.isSameAction || (keyboardInfo.heightIncrement != 0)) {
        [UIView animateWithDuration:keyboardInfo.animationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            switch (keyboardInfo.action) {
                case kHHKeyboardActionShow:{
                    //键盘出现
                    //自动调整
                    if (self.adaptiveController && self.adaptiveViews.count>0) {
                        [self adaptiveVC:self.adaptiveController withAdaptiveViews:self.adaptiveViews];
                    }
                    //block回调
                    if(self.animateWhenKeyboardAppearBlock != nil) {
                        self.animateWhenKeyboardAppearBlock(self, ++self.appearPostIndex, keyboardInfo.frameEnd, keyboardInfo.frameEnd.size.height, keyboardInfo.heightIncrement);
                    } else if (self.animateWhenKeyboardAppearAutomaticAnimBlock != nil) {
                        self.animateWhenKeyboardAppearAutomaticAnimBlock(self);
                    }
                    break;
                }
                case kHHKeyboardActionHide:{
                    //键盘消失
                    if(self.animateWhenKeyboardDisappearBlock != nil) {
                        self.animateWhenKeyboardDisappearBlock(self, keyboardInfo.frameEnd.size.height);
                        self.appearPostIndex = 0;
                    } else {
                        //自动恢复键盘
                        [self autoRestoreKeyboard];
                    }
                    break;
                }
                default:
                    break;
            }
        } completion:^(BOOL finished) {
//            if(self.printKeyboardInfoBlock != nil && self.keyboardInfo != nil) {
//                self.printKeyboardInfoBlock(self, keyboardInfo);
//            }
        }];
    }
}

- (void)triggerAction
{
    BCWeakObj(self);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        BCStrongObj(self);
        self.keyboardInfo = self.keyboardInfo;
    });
}

//MARK: - Notifcation
- (void)keyboardWillShow:(NSNotification *)notification
{
    [self handleKeyboard:notification keyboardAction:kHHKeyboardActionShow];
}

- (void)keyboardWillChangeFrame:(NSNotification *)notification {
    if(self.keyboardInfo.action == kHHKeyboardActionShow){
        //[self handleKeyboard:notification keyboardAction:kHHKeyboardActionShow];
    }
}

- (void)keyboardWillHide:(NSNotification *)notification {
    [self handleKeyboard:notification keyboardAction:kHHKeyboardActionHide];
}

- (void)keyboardDidHide:(NSNotification *)notification {
    //置空
    self.keyboardInfo = nil;
}

//MARK: - 处理键盘事件
- (void)handleKeyboard:(NSNotification *)notification keyboardAction:(NSInteger )keyboardAction
{
    //进入后台触发某些通知,不响应
    if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
        return;
    }
    if (!_zhenable) {
        return;
    }
    //解析通知
    NSDictionary *infoDict = [notification userInfo];
    CGRect frameBegin = [[infoDict objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect frameEnd = [[infoDict objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
    CGFloat previousHeight;
    if(self.keyboardInfo.frameEnd.size.height > 0) {
        previousHeight = self.keyboardInfo.frameEnd.size.height;
    } else {
        previousHeight = 0;
    }
    
    CGFloat heightIncrement = frameEnd.size.height - previousHeight;
    BOOL isSameAction;
    if(self.keyboardInfo.action == keyboardAction) {
        isSameAction = YES;
    } else {
        isSameAction = NO;
    }
    HHKeyboardInfo *info = [[HHKeyboardInfo alloc] init];
    [info fillKeyboardInfoWithDuration:kHHKeyboardDuration frameBegin:frameBegin frameEnd:frameEnd heightIncrement:heightIncrement action:keyboardAction isSameAction:isSameAction];
    self.keyboardInfo = info;
}

- (void)fillKeyboardInfoWithKeyboardInfo:(HHKeyboardInfo *)keyboardInfo duration:(CGFloat)duration frameBegin:(CGRect)frameBegin frameEnd:(CGRect)frameEnd heightIncrement:(CGFloat)heightIncrement action:(NSInteger )action isSameAction:(BOOL)isSameAction {
    keyboardInfo.animationDuration = duration;
    keyboardInfo.frameBegin = frameBegin;
    keyboardInfo.frameEnd = frameEnd;
    keyboardInfo.heightIncrement = heightIncrement;
    keyboardInfo.action = action;
    keyboardInfo.isSameAction = isSameAction;
}
@end










